package com.nsn.vs.sdm.component.svn;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import com.nsn.vs.sdm.component.svn.command.SvnCommand;
import com.nsn.vs.sdm.util.string.UtilString;


/**
 * The svn client manager
 * 
 * @author Jeccy.Zhao
 * 
 */
public class SvnClientManager 
{
	/**
	 * The LOGGER
	 */
	private static final Logger LOGGER = Logger.getLogger(SvnClientManager.class);
	
	/**
	 * The svn client manager instance
	 */
	private SVNClientManager manager = SVNClientManager.newInstance();
	
	/**
	 * The user name
	 */
	private String username;
	
	/**
	 * The user password
	 */
	private String password;
	
	/**
	 * The request id
	 */
	private String id;
	
	/**
	 * The buffered messages
	 */
	private static Map<String, StringBuffer> bufferMessages = 
		new HashMap<String, StringBuffer>();
	
	/**
	 * Authentication manager
	 */
	private ISVNAuthenticationManager authManager;
	
	static 
	{
		setupSvnKit ();
	}
	
	public SvnClientManager(String username, String password) 
	{
		this(username, password, null);
	}
	
	public SvnClientManager(String username, String password, String id) 
	{
		this.username = username;
		this.password = password;
		this.id = id;
		
		if (UtilString.isNotEmpty(id))
		{
			bufferMessages.put(id, new StringBuffer());
		}
		else
		{
			bufferMessages.put(this.toString(), new StringBuffer());
		}
		
		this.init();
	}
	
	/**
	 * Executes the specified command 
	 * and returns the last-updated revision number.
	 * 
	 * @param command
	 *          the svn command entity
	 * @return the last-updated revision number
	 * @throws Exception
	 */
	public long executeCommand(SvnCommand command) throws Exception 
	{
		long revision = command.execute();
		return revision;
	}
	
	/**
	 * Setup the svn kit
	 */
	private static void setupSvnKit() 
	{
		
		// For using over http:// and https://
		DAVRepositoryFactory.setup();
		
		// For using over svn:// and svn+xxx://
		SVNRepositoryFactoryImpl.setup();

		// For using over file:///
		FSRepositoryFactory.setup();
		
		
		
	}
	
	/**
	 * Initialization
	 */
	private void init() 
	{
		if (this.username != null && this.password != null) 
		{
			authManager = SVNWCUtil.createDefaultAuthenticationManager(
					this.username, this.password);
			this.manager.setAuthenticationManager(authManager);
		}
	}
	
	/**
	 * Browser the specified repository and returns all entries
	 * 
	 * @param root
	 * @param url
	 * @throws SVNException
	 */
	@SuppressWarnings({ "unchecked" })
	public List<String> listEntries (String path) throws SVNException
	{
		List<String> entryList = new ArrayList<String>();
		
		SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(path));
		repository.setAuthenticationManager(authManager);
		
		LOGGER.debug("Browsing repository: " + path);
		
		Collection<SVNDirEntry> entries = 
			(Collection<SVNDirEntry>) repository.getDir(
					"", -1, null, (Collection<SVNDirEntry>) null);
		
		Iterator<SVNDirEntry> itor = entries.iterator();
		
		while (itor.hasNext())
		{
			SVNDirEntry entry = itor.next();
			LOGGER.debug("Entry item found: " + entry.getName());
			entryList.add(entry.getName());
		}
		
		return entryList;
	}
	
	/**
	 * Appends message to 
	 * current message buffer pool.
	 * 
	 * @param message
	 *          the buffer message
	 */
	public void appendMessage (String message)
	{
		if (UtilString.isNotEmpty(this.id))
		{
			StringBuffer buf = bufferMessages.get(this.id);
			buf.append(message);
			buf.append("<br>");
		}
	}
	
	/**
	 * Obtains the message 
	 * with the specified id.
	 * 
	 * @param id
	 *         the client manager id
	 * @return message from the buffer pool against the manager id.
	 */
	public static String getMessage (String id)
	{
		String msg = "";
		if (bufferMessages.containsKey(id))
		{
			StringBuffer buf = bufferMessages.get(id);
			msg = buf.toString();
			buf.setLength(0);
		}
		return msg;
	}
	
	/**
	 * Returns true if it exists 
	 * the buffer message against the specified id.
	 * 
	 * @param id
	 *         the client manager id.
	 * @return true if the buffer message exists with the id.
	 */
	public static boolean containMessage (String id)
	{
		return bufferMessages.containsKey(id);
	}
	
	/**
	 * Clears the buffer message 
	 * against the specified client manager id.
	 * 
	 * @param id
	 *         the client manager id.
	 */
	public static void clear (String id)
	{
		if (bufferMessages.containsKey(id))
		{
			bufferMessages.remove(id);
		}
	}
	
	public void setManager(SVNClientManager manager) 
	{
		this.manager = manager;
	}
	
	public SVNClientManager getManager() 
	{
		return manager;
	}

	public void setUsername(String username) 
	{
		this.username = username;
	}

	public String getUsername() 
	{
		return username;
	}

	public void setPassword(String password) 
	{
		this.password = password;
	}

	public String getPassword() 
	{
		return password;
	}

	public static void setBufferMessages(Map<String, StringBuffer> bufferMessages)
	{
		SvnClientManager.bufferMessages = bufferMessages;
	}

	public static Map<String, StringBuffer> getBufferMessages()
	{
		return bufferMessages;
	}

	public void setId(String id)
	{
		this.id = id;
	}

	public String getId()
	{
		return id;
	}
}
